"""此模块用于统一和简化datatoolsobj包的Excel数据读取和处理功能。
"""
import os

import pandas as pd
from datatoolsobj.utils import create_dir, beep
from datatoolsobj.excel.exceldirwalk import ExcelDirWalk
from datatoolsobj.excel.excelhub import ExcelHub
from datatoolsobj.excel.excelconcat import ExcelConcat
from datatoolsobj.templates.finace_default import FinaceType
from datatoolsobj.excel.multi_line_hdr_hub import MultiLineHdrHub
from datatoolsobj.excel.dump_work_files import DumpWorkFiles

import logging

logging.basicConfig(level="INFO")

mylog = logging.getLogger()


class MyExcel():
    '''实现功能的主类。提供傻瓜式操作。
    '''

    def __init__(self, dir_path, project_name,from_project =None,excel_dir_struct_conf_path=None, used_sheet_columns_conf_path=None,
                 excel_multi_hdr_conf_path=None,excel_dir_conf_dir=None, excel_columns_conf_dir=None, beep=False):
        '''初始化一个MyExcel类。
        dir_path:用于遍历处理的包函Excel文件的根目录。
        project_name:此次操作项目名称，用于区分不同的处理操作。
        from_project:参考项目名称，若为非空，则查找[from_project +[使用表配置|使用列配置]+_参考]作为参考填充本项目相关配置文件。
        beep:一个阶段性处理完成，需要人工干于的时候是否蜂鸣提示，默认关闭。
        '''
        if os.path.isdir(dir_path):
            self.dir_path = dir_path
        else:
            self.dir_path = os.path.dirname(dir_path)
        #self._dir_path = dir_path
        self._project_name = project_name

        create_dir('conf')
        mylog.debug("created conf dir.")

        # 使用表配置部分
        if not excel_dir_struct_conf_path:
            self._excel_dir_struct_conf_path = self._project_name + "使用表配置"
        else:
            self._excel_dir_struct_conf_path = excel_dir_struct_conf_path
        if not excel_dir_conf_dir:
            self._excel_dir_conf_dir = 'conf'
        else:
            self._excel_dir_conf_dir = excel_dir_conf_dir

        # 使用多行表头配置部分
        if not excel_multi_hdr_conf_path:
            self._excel_multi_hdr_conf_path = self._project_name + "多行表头用列配置"
        else:
            self._excel_multi_hdr_conf_path = excel_multi_hdr_conf_path


        # 使用列配置部分
        if not used_sheet_columns_conf_path:
            self._used_sheet_columns_conf_path = self._project_name + "使用列配置"
        else:
            self._used_sheet_columns_conf_path = used_sheet_columns_conf_path
        if not excel_columns_conf_dir:
            self._excel_columns_conf_dir = 'conf'
        else:
            self._excel_columns_conf_dir = excel_columns_conf_dir

        #使用参考项目配置文件填充本项目配置文件
        self._from_project = from_project
        if self._from_project:
            mylog.info("检测到配置参考项目[{}]".format(self._from_project + "使用表配置"))
            self._from_excel_used_sheets = self._project_name + "使用表配置" + "_参考"
            self._from_excel_used_columns = self._project_name + "使用列配置" + "_参考"
        else:
            self._from_excel_used_sheets = None
            self._from_excel_used_columns = None

        self._beep = beep
        self._step = 0

    def findUseSheets(self):
        '''第一步：从指定的目录获取所有的Excle文件，并生成要使用的文件配置，进行手动处理。
        '''
        self.edw = ExcelDirWalk(self.dir_path, self._excel_dir_struct_conf_path,self._from_excel_used_sheets,conf_dir=self._excel_dir_conf_dir)
        if self.edw.isNewDir():
            self.edw.outUsedExcelConfFile()
            if self._beep:
                beep()
            input("此处暂停，输出了Excel文件结构配置文件[{}]，手动配置".format(self._excel_dir_struct_conf_path))
        self.edw.inUsedExcelConfFile()
        self.used_sheets = self.edw.getExcelDirDataFrame()
        self._step = 1
        return self.used_sheets

    def dumpWorkFiles(self):
        """
        第二步：根据第一步所得使用表的结果，将用到的所有数据文件按照项目名称拷贝到数据转储目录下。其中需要对多行结构在转储前进行转换。
        """
        if self._step < 1:
            print('请先进行findUseSheets获取要使用的数据表。')
            mylog.critical("请先进行findUseSheets获取要使用的数据表!")
            return

        # 获取所有多选表。
        used_sheets = self.used_sheets
        multi_line = used_sheets.loc[~used_sheets['单行列名'].isin(['是','Y',True,'TRUE','True'])]
        if not multi_line.empty:
            # 根据标识获取表头结构
            self.mlh = MultiLineHdrHub(used_sheets,self._excel_multi_hdr_conf_path,conf_dir=self._excel_columns_conf_dir)
            if self.mlh.isNewDir():
                self.mlh.outMultiLineConfFile()
                if self._beep:
                    beep()
                input(
                    "此处暂停，输出了所有Sheet表中表头区域存在多行的列名情况[{}]，手动配置".format(self._excel_multi_hdr_conf_path))
            self.mlh.inMultiLineConfFile()
            self.mlh.transfer()
            # 获取所有多行表头列列表  后续可直接使用
            #mutili_sheets = self.mlh.getMultiUsedSheets()
            # 设置多选中行信息配置参数
            used_columns_dict = self.mlh.getMultiUsedColumnsDict()
        else:
            used_columns_dict = None

        # 所有用到的文件进行统一备份
        dwf = DumpWorkFiles(used_sheets, used_columns_dict=used_columns_dict)
        dwf.dumpWorkFiles()
        # if not multi_line.empty:
        #     dwf = DumpWorkFiles(self.mlh.getMultiUsedSheets(),used_columns_dict=self.mlh.getMultiUsedColumnsDict())
        #     dwf.dumpWorkFiles()
        # else:
        #     dwf = DumpWorkFiles(used_sheets)
        #     dwf.dumpWorkFiles()
        self._step = 2

    def findUseColumns(self):
        '''第二步：根据第一步所得使用表的结果，分析获取所有用到的表头中的列，形成配置文件，进行手动处理。
        '''
        if self._step < 1:
            print('请先进行findUseSheets获取要使用的数据表。')
            mylog.critical("请先进行findUseSheets获取要使用的数据表!")
            return
        self.ehb = ExcelHub(self.used_sheets, self._used_sheet_columns_conf_path,self._from_excel_used_columns,conf_dir=self._excel_columns_conf_dir)
        if self.ehb.isNewDir():
            self.ehb.outUsedSheetColumnsConfFile()
            if self._beep:
                beep()
            input("此处暂停，输出了所有Sheet表涉及的列名结构[{}]，手动配置".format(self._used_sheet_columns_conf_path))
        self.ehb.inUsedSheetColumnsConfFile()
        self.used_columns = self.ehb.getUsedSheetColumnsDataFrame()
        self._step = 2
        return self.used_columns

    def concatData(self):
        '''第三步：根据第二步所得到的使用的列，读取数据文件，并自动进行合并连接。
        '''
        if self._step < 2:
            print('请先进行findUseColumns获取要使用列。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            return
        self.ec = ExcelConcat(self.used_columns)
        self.data = self.ec.concat()
        if self._beep:
            beep()
        self._step = 3
        return self.data

    def walkExcelHeaders(self, apply_func=None):
        '''遍历每个Sheet表的文件头部分内容，对其应用指定的函数。
        apply_func:要应用的函数。原型为walk_excel_headers_func(data,file_info)。
            其中data为传入的头部数据部分DataFrame，file_info为存在于ExcelDirWalk中的关于此表的信息。
        '''
        if self._step < 2:
            print('请先进行findUseColumns获取要使用列。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            return
        if apply_func:
            result = self.ehb.walkExcelHeaders(apply_func)
        else:
            result = self.ehb.walkExcelHeaders()
        return result

    def getExcelLedger(self):
        '''遍历每个Sheet表的文件头部分内容，根据其类型，使用对应财务数据模板获取科目内容。
        '''
        if self._step < 2:
            print('请先进行findUseColumns获取要使用列。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            return

        result = self.ehb.walkExcelHeaders(FinaceType.findLedger)

        return pd.DataFrame(result)

    def play(self):
        """自动执行所有操作。
        """
        self.findUseSheets()
        self.findUseColumns()
        return self.concatData()

    def dump(self):
        self.findUseSheets()
        self.dumpWorkFiles()

    def getData(self):
        '''自动处理后，获生成的数据。
        '''
        if self._step < 3:
            print('请先进行findUseColumns获取要使用列。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            raise ValueError('请先进行concatData获取要使用列。')
        return self.data

    def getUsedSheets(self):
        '''获取使用的文件配置数据
        '''
        if self._step < 1:
            print('请先进行findUseSheets获取要使用的数据表。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            return
        return self.used_sheets

    def getUsedColumns(self):
        '''获取使用的列配置数据
        '''
        if self._step < 3:
            print('请先进行findUseColumns获取要使用列。')
            mylog.critical("请先进行findUseColumns获取要使用列!")
            raise ValueError('请先进行concatData获取要使用列。')
        return self.used_columns
